package cn.itcast.netty.c4;

import cn.itcast.netty.c1.ByteBufferUtil;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

@Slf4j
public class Server {

    public static void main(String[] args) throws Exception {


        //1.创建Selector-管理多个channel
        Selector selector = Selector.open();

        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.configureBlocking(false);//非阻塞，影响到accept()
        ssc.bind(new InetSocketAddress(8080));

        //3.将channel注册到Selector,SelectionKey事件发生后，可以得到事件和具体的channel，关注OP_ACCEPT事件
        // 事件accept-会在有连接请求时出发
        // 事件connect 是客户端连接建立后触发
        // 事件tread  可读事件
        // 事件write 可写事件
        SelectionKey sscKey = ssc.register(selector, 0, null);
        sscKey.interestOps(SelectionKey.OP_ACCEPT);

        log.debug("register-key :{}", sscKey);
        while (true) {
            //3.没有事件就阻塞，有事件则向下运行,有事件不处理时，不会阻塞
            //事件发生后，要么处理、要么取消
            selector.select();
            //4 处理事件，包含了所有发生的事件
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                log.debug("key :{}", key);
                //处理key过后，要从selectedKeys中删除
                iterator.remove();

                // 5 区分事件类型
                if (key.isAcceptable()) {
                    ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
                    SocketChannel sc = serverSocketChannel.accept();
                    sc.configureBlocking(false);
                    //将channel注册到Selector,关注OP_READ事件,将ByteBuffer作为附件关联到key上
                    ByteBuffer buffer = ByteBuffer.allocate(16);//attachment
                    SelectionKey scKey = sc.register(selector, 0, buffer);
                    scKey.interestOps(SelectionKey.OP_READ);
                    log.debug("sc :{}", sc);
                } else if (key.isReadable()) {
                    try {
                        SocketChannel channel = (SocketChannel) key.channel();
                        //获取key上关联的attachment
                        ByteBuffer buffer = (ByteBuffer) key.attachment();
                        int read = channel.read(buffer);
                        if (read == -1) { // -1正常断开
                            key.cancel();
                        } else {
                            split(buffer);
                            if (buffer.position() == buffer.limit()) {
                                //扩容
                                ByteBuffer newBuffer = ByteBuffer.allocate(buffer.capacity() * 2);
                                buffer.flip(); //读模式
                                newBuffer.put(buffer);//
                                key.attach(newBuffer);//新的attach
                            }

                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                        //因为客户端异常-断开了，需要key 取消（从selector的key集合中正真删除）
                        key.cancel();
                    }

                }


            }

        }


    }

    private static void split(ByteBuffer source) {
        source.flip();//读模式
        for (int i = 0; i < source.limit(); i++) {
            if (source.get(i) == '\n') {
                int length = i + 1 - source.position();
                ByteBuffer target = ByteBuffer.allocate(length);
                //从source读，向target写
                for (int j = 0; j < length; j++) {
                    target.put(source.get());
                }
                ByteBufferUtil.debugAll(target);
            }
        }

        source.compact();//写模式

    }
}
